try:
    import cv2
    from PIL import ImageFont, ImageDraw, Image
    import numpy as np
    from os import system
except ModuleNotFoundError as err:
    print("存在未安装的模块：" + err.msg)
    exit(1)


def Chinese_Counter(string: str) -> int:
    """计算字符串里中文字符数量"""
    counter = 0
    for a_char in string:
        if (ord(a_char) >= 256):
            counter += 1

    return counter


def Total_length(string: str) -> int:
    """计算字符串里总字符数量"""
    counter = string.__len__()
    for a_char in string:
        if (ord(a_char) >= 256):
            counter += 1

    return counter


def DrawWord(font_size: int, font_path: str,
             print_str: str) -> list[list[int]]:
    """给出字体取模结果"""
    font_var = ImageFont.truetype(font_path, font_size)  # 字体文件
    string_length = Total_length(print_str)  # 有多少个半角字符宽
    image_var = np.zeros((font_size, font_size // 2 * string_length, 3),
                         dtype=np.uint8)  # 创建空白画布，对于某些字体可能需要增加第一个参数
    Img_Pil = Image.fromarray(image_var)
    draw_var = ImageDraw.Draw(Img_Pil)

    draw_var.text((0, 0), print_str, font=font_var, fill=(0, 0, 255))  # 打字
    image_var = np.array(Img_Pil)

    x_max = font_size
    y_max = int(image_var.size // (font_size * 3))  # y方向像素个数

    point = [[0 for _ in range(y_max)] for _ in range(x_max)]

    for x_ord in range(x_max):
        for y_ord in range(y_max):
            if (image_var[x_ord, y_ord][2] > 70):  # 对于一些英文数字可能需要调整这个阈值，中文不需要
                point[x_ord][y_ord] = 1

    return point


def Draw_LED_Picture(point_map: list[list[int]],
                     pix_size: int,
                     print_color,
                     output_file: str,
                     yrange: int = -1,
                     ybegin: int = 0) -> None:
    """根据点阵画点"""
    xrange = point_map.__len__()
    if (yrange == -1):
        yrange = point_map[0].__len__()
    image_var = np.zeros((pix_size * xrange, pix_size * yrange, 3),
                         dtype=np.uint8)

    for x_ord in range(xrange):
        for y_ord in range(min(yrange, point_map[0].__len__() - ybegin)):
            if (point_map[x_ord][y_ord + ybegin] == 1):
                cv2.circle(image_var,
                           center=(pix_size // 2 + pix_size * y_ord,
                                   pix_size // 2 + pix_size * x_ord),
                           radius=pix_size // 2 - 1,
                           color=print_color,
                           thickness=-1)  # 如果这一点为1则画圆

    cv2.imwrite(output_file, image_var)
    return


def Make_Image(font_size: int, pix_size: int, font_path: str,
               point_color) -> None:
    """生成单个字符串的图片"""
    output_file = input("输出文件路径，忽略则输出至 font.png 里：")
    if (output_file == ""):
        output_file = "./image/font.png"
    else:
        output_file = "./image/" + output_file
    system("mkdir -p image")
    point_map = DrawWord(font_size, font_path, input("输入待转换的字符串："))
    Draw_LED_Picture(point_map, pix_size, point_color, output_file)
    print("生成在 {} 里。".format(output_file))
    return


def Make_Video(font_size: int,
               pix_size: int,
               font_path: str,
               point_color,
               fps: int = 30) -> None:
    output_file = input("输出文件路径，忽略则输出至 font.mp4 里：")
    if (output_file == ""):
        output_file = "./video/font.mp4"
    else:
        output_file = "./video/" + output_file
    system("mkdir -p video; mkdir -p video/temp")
    words = input("输入需要转换的字符串：")
    length = int(input("屏幕宽度（一个汉字是 {} 长度）：".format(font_size)))
    prompt = input("请输入：滚动至文字尾出现(B)或文字尾消失(E)：")
    if (prompt == "E"):
        max_begin = max(Total_length(words) * font_size // 2, 0)
    elif (prompt == "B"):
        max_begin = max(Total_length(words) * font_size // 2 - length, 0)
    else:
        print("选择错误。")
        return
    # 生成文字图像
    mat = DrawWord(font_size, font_path, words)
    # 创建一个视频流
    video = cv2.VideoWriter(output_file, cv2.VideoWriter_fourcc(*"mp4v"), fps,
                            (length * pix_size, font_size * pix_size))
    # 依次生成每一个图片并读取
    for index in range(max_begin):
        png_path = "./video/temp/{}.png".format(index)
        Draw_LED_Picture(mat, pix_size, point_color, png_path, length, index)
        video.write(cv2.imread(png_path))
    video.release()
    system("rm -r ./video/temp")


if __name__ == "__main__":
    # 这几行可能需要自行调整
    font_size = 16  # 每列有多少个点，越大字体越逼真
    pix_size = 12  # 像素大小，越大图像越清晰，建议不小于12
    font_path = "/usr/share/fonts/windows/simsun.ttc"  # 宋体字体文件，需要其他字体请自行替换
    point_color = (0, 0, 255)  # (0,0,255) 为红色，(2,215,255) 为金色，(255,0,0) 为绿色
    fps = 30  # 视频帧率

    # 程序部分
    choice = input("请输入：生成图片(T)或生成视频(S)：")
    if (choice == "T"):
        Make_Image(font_size, pix_size, font_path, point_color)
    elif (choice == "S"):
        Make_Video(font_size, pix_size, font_path, point_color, fps)
    else:
        print("选择错误。")
